home *** CD-ROM | disk | FTP | other *** search
- Path: hubcap.clemson.edu!hubcap!mjs
- From: mjs@hubcap.clemson.edu (M. J. Saltzman)
- Newsgroups: comp.lang.c
- Subject: Re: NEwbie: How to return a multi-dimensional array from function?
- Date: 15 Mar 96 18:59:48 GMT
- Organization: Clemson University
- Message-ID: <mjs.826916388@hubcap>
- References: <4hp273$8bu@news.xs4all.nl> <31404CE9.1A4A@mc.net> <mjs.826298629@hubcap> <4ib78s$6gv@news.bridge.net>
- NNTP-Posting-Host: hubcap.clemson.edu
- X-Newsreader: NN version 6.5.0 #1
-
- psycho@bridge.net (Gary Thompson) writes:
-
- |mjs@hubcap.clemson.edu (M. J. Saltzman) wrote:
-
- |>Sean Park <spark@mc.net> writes:
-
- |>>Anthony Moendir wrote:
- |>>>
- |>>> I want to return a multidimensional array from a function,
- |>>> something like this:
- |>>>
- |>>> char *Foo();
- |>>> int main()
- |>>> {
- |>>> char tmp[10][5];
- |>>> tmp=Foo();
- |>>> }
- |>>>
- |>>> char *Foo()
- |>>> {
- |>>> char tmp[10][5];
-
- |>Two things: (1) If you are going to use the value of tmp outside of Foo(),
- |>then you need to declare
- |> static tmp[10][5];
- |>Otherwise the storage may disappear when you return from Foo().
-
- |No, declaring it as static will only retain the value in the foo() function, if
- |you call it more than once. You CANNOT use a value declared in a subfunction in
- |MAIN. You would have to remove both TMP declarations from MAIN and FOO and
- |declare the thing globally outside of main.
-
- But we return the address at the end of the function. If the variable
- is static, the pointer in main() can be used to access that memory
- between calls to Foo().
-
- |>>> //do something
- |>>> return(tmp);
- |> ^ ^ Parentheses not required here.
- |>>> }
-
- |Makes no difference. They are compiled the same either way. Who would care
- |about saving two bytes code space?
-
- I didn't say they were forbidden, only unnecessary. I point it out
- only because some people don't seem to realize it.
-
- |>(2) When you use tmp in an expression, the compiler replaces the array
- |>name with a constant pointer to its first element. (Among other
- |>consequences, this means that arrays can't appear on the left side of
- |>assignments.) In this case, the first element has type
- |>array-of-15-chars, so a pointer to it is a
- |>pointer-to-array-of-15-chars. That's the type that the function
- |>should return, and the type of the variable that you assign it to.
- |>Thus, Foo() needs to be declared
-
- |> char (*Foo())[5];
- |>and the tmp in main() should be
- |> char (*tmp)[5];
-
- |WHAT??? You just declared five FUNCTION pointers pointed to nothing! If you
- |ran that, you'd get a NULL pointer error. It wouldn't even run! Again,
- |declaring char (*tmp)[5] is declaring an array of five pointers to chars and
- |assigning them to nothing... which will give you a NULL POINTER error AGAIN.
-
- The declaration of Foo is parsed as follows (inside-out, postfix-first,
- respecting parentheses):
-
- Foo is a function returning a pointer to an array of 5 chars.
-
- Which is what I said it was (except I mistyped 5 as 15).
-
- The declaration of the tmp in main() is:
-
- tmp is a pointer to an array of 5 chars.
-
- So the assignment
-
- tmp = Foo()
-
- is legal (in that the types of the objects on both sides are the same).
-
- BTW, If you want an array of five pointers to char, that's
-
- char *tmp[5];
-
- An array of five pointers to functions returning char is
-
- char (*tmp[5])();
-
- |>>>[...]
-
- |>Another technique for getting the result back is to pass the array in as an
- |>argument, as is done below (with corrections).
-
- |>>You could pass the pointer to the array to the function. That way the
- |>>function itself will fill your array addresses rather than returning
- |>>redundant data. You might try:
-
- |>>void foo(char *tmp);
- |> ^^^^^^^^^ Here, tmp should be declared char (*tmp)[5].
-
- |That wont work. All pointers, require either 2 or 4 bytes (I forget which).
-
- Sometimes 2, sometimes 4, sometimes more, but it doesn't matter, since
- there is no type punning anywhere here; my tmp is a pointer to an array
- of 5 chars.
-
- |You cannot pass data this way. Chars only take up one byte. If you pass an
- |array of chars this way, you will get scrambled data at the other end. It will
- |try to interpret the passed chars as pointer addresses. You will have to pass
- |an array of POINTERS for this to work. And you cannot pass arrays of anything.
-
- I'm not passing either a character or an array of characters (or even
- an array of pointers). Again, my declaration is for a pointer to an
- array of 5 chars. In this case, it's a pointer to the first array of
- 5 chars in an array of 10 such arrays.
-
- |>>int main()
- |>>{
- |>> char tmp[10][5];
- |>> foo(tmp);
- |>> return 0;
- |>>}
- |>>void foo(char *tmp)
- |> ^^^^^^^^^ Here, tmp should be declared char (*tmp)[5].
-
- |Ok, since you declared foo() to accept only an array of five pointers at 2 bytes
-
- No, a pointer to an array of 5 chars.
-
- |each, why are you passing it a single pointer? When you pass it like foo(tmp),
- |you are only passing it a single pointer to the beginning of the 2d array. You
- |will get one pointer and the rest garbage.
-
- I ask for only one pointer (to an array of 5 chars), and I pass only
- one pointer (the address of the first array of 5 chars in an array of 10
- such arrays).
-
- |Besides, you are ignoring the question. You are passing the data TO foo, he
- |wants to return it from FOO. Make it simple... There are several ways of doing
-
- I'm passing the address of a region of memory in main() (the 2-D
- array tmp) that will be modified inside the function. That achieves the
- desired result, namely that the array in the calling function have the
- value calculated by the called function.
-
- |it easy...
- |--------------------
- |void foo(void);
- |char tmp[10][5];
-
- |void main(void)
-
- Do you read none of the discussions here? You need to declare main as
-
- int main(void)
-
- |{
- | foo();
- | /* do something else with tmp */
- |}
-
- |void foo(void)
- |{
- | /* do something with tmp */
- |}
- |-----------------
- |That example allows you to access TMP within both main and foo. Problem is,
- |it's not very good with security... tmp can be modified by ALL functions....
- |not recommended if it's something critical.... This is a little more complicated
- |but still easy...
-
- I agree with everything you say here. Another disadvantage of this
- technique is that foo() cannot modify anything *other* than the global
- variable tmp. All it accomplishes is to move some code out of line.
-
- |-----------------
- |void foo(char *);
- |main()
- |{
- | char tmp[10][5];
- | foo(tmp);
- |}
-
- |char *foo(char *tmp2)
- |{
- | /* You can access tmp2 exactly like tmp... tmp2[10][5]...etc */
- |}
- |--------------------
- |There are a few quirks with this also... tmp2 is accessed exactly like tmp
- |because it is the same thing. tmp and tmp2 both access the same space. That's
- |why you don't have to return anything. You can use tmp instead of tmp2, but it
- |makes no difference. tmp in main is a different variable than tmp in foo. I
- |like to use different variable names for the sake of clarity.
-
- No, no, no! tmp and tmp2 are not accessed the same way at all. tmp
- is an array of 10 arrays of 5 chars. When the name of the array is
- used as a value (as in the call to foo), it is replaced by a pointer
- to the first element of the first array, in this case, a pointer to
- the first of the ten arrays of 5 chars. The type of this value is
- (char (*)[5]) (i.e., pointer to array of 5 chars). This is not in any
- way the same as a pointer to a single char, like tmp2.
-
- Think about this: tmp2[3] is a character, but tmp[3] is an array of 5
- characters. You can't write
-
- tmp2[3] = tmp[3];
-
- (even if both were in scope). You have to pick one of the five characters
- in tmp[3]:
-
- tmp2[3] = tmp[3][3];
-
- You can't write tmp2[3][3] at all, since tmp2[3] is not a pointer or
- an array.
-
- |One problem with C is that the ONLY way you can pass the data in an array
- |without passing just the pointer is by using a STRUCT. passing the name of a
- |struct is the only thing that will pass the data and not a pointer to the data.
-
- But that wasn't my goal (or the original poster's). My goal was to
- pass a pointer, so that the function could modify the array whose
- address was passed. Furthermore, in this case, you are not passing
- an array anyway--you are now passing a struct.
-
- |If you truly want to keep your variables independant, you will have to use a
- |struct.
-
- |That is... unless you want to program in C++... you can then use the first
- |example and declare which functions have permission to modify it.
-
- But that's a whole different issue, not relevant to comp.lang.c.
-
- To recap: There are essentially two ways to return a 2-D table of values
- from a function:
-
- (1) Return the address of a static array.
-
- char (*Foo())[5]; /* function returning pointer to array of 5 chars */
-
- int main()
- {
- char (*tmp)[5];
-
- tmp = Foo();
- /* use tmp--note that you can access tmp[i][j], just as you can
- access tmp2[i][j] inside the body of Foo(), and in fact, it is
- tmp2[i][j] that is accessed */
-
- return 0;
- }
-
- char (*Foo())[5]
- {
- static char tmp2[10][5];
-
- /* do something to tmp2 */
-
- return tmp2; /* return address of first of tmp2's arrays of 5 chars,
- just as if we'd written return &tmp2[0] */
- }
-
-
- (2) Pass the address of an array as a parameter and modify the array
- it points to.
-
- void Foo(char (*)[5]); /* function taking pointer to array of 5 chars */
-
- int main()
- {
- char tmp[10][5];
-
- Foo(tmp); /* pass address of first of tmp's arrays of 5 chars
- just as if we'd written Foo(&tmp[0]) */
- return 0;
- }
-
- void Foo(char (*tmp2)[5])
- {
- /* do something to tmp2--note that now you can access tmp2[i][j]
- here, just as you access tmp[i][j] in main, and in fact, it
- is tmp[i][j] that is accessed, if you call Foo(tmp) */
- }
-
- Here, we could have declared Foo equivalently as
-
- void Foo(tmp2[][5]);
-
- Note that these are exactly the same ideas that we use if we want to
- return a 1-D array of values. In fact, we *are* returning a 1-D array
- of values; it's just that each value is an array of 5 chars.
-
- Is that clear, now? If not, may I recommend a careful perusal of the
- relevant parts of the FAQ?
- --
- Matthew Saltzman
- Clemson University Math Sciences
- mjs@clemson.edu
-